package com.jkgh.test {

	import com.jkgh.remedium.*;
	import com.jkgh.remedium.objects.*;
	import com.jkgh.remedium.objects.messages.*;
	import com.jkgh.remedium.objects.messages.ins.*;
	import com.jkgh.remedium.objects.messages.out.*;
	import com.jkgh.remedium.states.*;
	import com.jkgh.remedium.tools.*;
	
	/**
	 * A server controller for something.
	 */
	public class MainServerController extends RemediumMethodObject {
		
		/**
		 * Does command.
		 * 
		 * @param a A command to do.
		 */
		public function doIt(a:String):void {
			throw new AbstractMethodNotImplementedError();
		}
		
		/**
		 * Does the usual thing.
		 */
		public function doTheUsual():void {
			throw new AbstractMethodNotImplementedError();
		}
		
		/**
		 * Does the ultimate thing.
		 * 
		 * @param ms Other parties.
		 * @param sh Command id.
		 * @param returner Should return int: A new id for things. 
		 */
		public function doSomethingElseWith(ms:Vector.<MainServerController>, sh:int, onReturn:Function):void {
			throw new AbstractMethodNotImplementedError();
		}
		
		// --------------------------------------------------------------------------------
		
		public function MainServerController(remedium:RemediumSystem, hostID:int = -1, objectID:int = -1, registry:RemediumSystem = null) {
			super(remedium, hostID, objectID, registry);
		}
		
		override public final function call(remedium:RemediumSystem, message:RemediumInMessage, callID:int, methodID:int, callback:Function):void {
			switch (methodID) {
				
				case 0:
					RemediumTools.consumeString(remedium, function(aa:String):void {
						doIt(aa);
						callback();
					});
					break;
				
				case 1:
					doTheUsual();
					callback();
					break;
				
				case 2:
					remedium.setState(MainServerController.createVectorConsumingState(message, function(cms:Vector.<MainServerController>):void {
						RemediumTools.consumeInt(remedium, function(csh:int):void {
							
							doSomethingElseWith(cms, csh, function(cr:int):void {
								var cresponder:RemediumC2SIntResponder = new RemediumC2SIntResponder(callID, cr);
								cresponder.produce(remedium);
							});
							callback();
						});
					}));
					break;
			}
		}
		
		public static function createVectorConsumingState(message:RemediumInMessage, future:Function):RemediumState {
			return new GatheringState(4, function(remedium:RemediumSystem):void {
				var length:int = remedium.produceInt();
				if (length == -1) {
					future(null);
				} else if (length == 0) {
					future(new Vector.<MainServerController>());
				} else {
					var i:int = 0;
					var result:Vector.<MainServerController> = new Vector.<MainServerController>(length, true);
					var onO:Function = function(o:MainServerController):void {
						result[i++] = o;
						if (i == length) {
							future(result);
						} else {
							remedium.setState(createConsumingState(message, onO));
						}
					};
					remedium.setState(createConsumingState(message, onO));
				}
			});
		}
		
		public static function createConsumingState(message:RemediumInMessage, future:Function):RemediumState {
			return new GatheringState(1, function(remedium:RemediumSystem):void {
				
				switch (remedium.produceByte()) {
					
					case RemediumConstants.NULL:
						future(null);
						break;
					
					case RemediumConstants.HISTORY:
						future(MainServerController(message.fromHistory(remedium.produceInt())));
						break;
					
					case RemediumConstants.VALUE:
						consumeContent(remedium, message, future);
						break;
				}
			});
		}
		
		private static function consumeContent(remedium:RemediumSystem, message:RemediumInMessage, future:Function):void {
			remedium.setState(new GatheringState(8, function(remedium:RemediumSystem):void {
			
				var hostID:int = remedium.produceInt();
				var objectID:int = remedium.produceInt();
				
				var methodObject:MainServerController = MainServerController(remedium.getMethodObject(hostID, objectID));
				if (methodObject == null) {
					methodObject = new MainServerControllerRedirector(hostID, objectID, remedium);
				}
				
				future(methodObject);
			}));
		}
	}
}

import com.jkgh.remedium.RemediumSystem;
import com.jkgh.remedium.objects.messages.out.RemediumC2SCaller;
import com.jkgh.remedium.tools.RemediumTools;
import com.jkgh.test.MainServerController;

class MainServerControllerRedirector extends MainServerController {
	
	private var remedium:RemediumSystem;
	
	public function MainServerControllerRedirector(hostID:int, objectID:int, remedium:RemediumSystem) {
		super(null, hostID, objectID, remedium);
		this.remedium = remedium;
	}
	
	override public function doIt(a:String):void {
		var caller:RemediumC2SCaller = new RemediumC2SCaller(hostID, objectID, 0, 0, function():void {
			RemediumTools.produceString(remedium, a);
		});
		caller.produce(remedium);
	}
	
	override public function doTheUsual():void {
		var caller:RemediumC2SCaller = new RemediumC2SCaller(hostID, objectID, 1, 0, function():void {
		});
		caller.produce(remedium);
	}
	
	override public function doSomethingElseWith(ms:Vector.<MainServerController>, sh:int, onReturn:Function):void {
		var caller:RemediumC2SCaller = new RemediumC2SCaller(hostID, objectID, 2, remedium.registerCall(onReturn), function():void {
			RemediumTools.produceObjectArray(remedium, caller, ms);
			remedium.consumeInt(sh);
		});
		caller.produce(remedium);
	}
}
